package com.bootx.service.impl;

import com.bootx.common.CommonAttributes;
import com.bootx.common.Page;
import com.bootx.common.Pageable;
import com.bootx.dao.RedPackageDao;
import com.bootx.entity.OpenAiConfig;
import com.bootx.entity.RedPackage;
import com.bootx.pojo.RedPackageInfo;
import com.bootx.repository.RedPackageRepository;
import com.bootx.service.OpenAiConfigService;
import com.bootx.service.RedPackageService;
import com.bootx.service.RedPackageStatisticsService;
import com.bootx.util.DateUtils;
import jakarta.annotation.Resource;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.content.Media;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.FileSystemResource;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.MimeTypeUtils;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author black
 */
@Service
public class RedPackageServiceImpl extends BaseServiceImpl<RedPackage,Long> implements RedPackageService {

    @Resource
    private OpenAiConfigService openAiConfigService;

    @Resource
    private ChatClient chatClient;

    @Resource
    private RedPackageDao redPackageDao;
    @Resource
    private RedPackageStatisticsService redPackageStatisticsService;

    @Resource
    private RedPackageRepository redPackageRepository;

    @Override
    public void parse() {
        String openParse = redisService.get("openParse");
        OpenAiConfig openAiConfig = openAiConfigService.find(1L);
        if (openAiConfig == null) {
            System.out.println("apiKey没有配置");
            return;
        }
        if (openAiConfigService.getCount() <= 0) {
            System.out.println("11111剩余次数没有了，请充值");
            return;
        }
        if (!StringUtils.equalsIgnoreCase(openParse, "1")) {
            System.out.println("未开启解析");
            return;
        }
        File root = new File("D:\\red\\redpackage");
        File[] files = root.listFiles();
        if (files == null || files.length == 0) {
            // 小于1的话 不需解析
            return;
        }
        UserMessage.Builder builder = UserMessage.builder();
        builder.text(CommonAttributes.PROMPT);
        for (int i = files.length-1; i>0; i--) {
            File file = files[i];
            System.out.println(file.getName());
            if(StringUtils.equalsAnyIgnoreCase(redisService.get("screenshot"),file.getName())){
                continue;
            }
            long start = System.currentTimeMillis();
            File[] children = file.listFiles();
            if (children == null || children.length == 0) {
                try {
                    FileUtils.deleteDirectory(file);
                } catch (Exception ignored) {
                }
                continue;
            }
            List<Media> medias = new ArrayList<>();
            for (File child : children) {
                FileSystemResource resource = new FileSystemResource(child);
                medias.add(new Media(MimeTypeUtils.IMAGE_PNG, resource));
            }
            if (medias.size() > 1) {
                builder.media(medias);
                UserMessage userMessage = builder.build();
                try {
                    RedPackageInfo entity = chatClient.prompt().messages(userMessage).call().entity(new ParameterizedTypeReference<RedPackageInfo>() {
                    });
                    if (entity != null) {
                        entity.setBatchId(Long.valueOf(file.getName()));
                        entity.setAmount(0.0);
                        for (RedPackageInfo.RedPackageItem redPackageItem : entity.getRedPackageItemList()) {
                            entity.setAmount(entity.getAmount() + redPackageItem.getAmount());
                        }
                        save(entity);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    openAiConfigService.updateCount(medias.size()*-1);
                    try {
                        FileUtils.deleteDirectory(file);
                    } catch (Exception ignored) {
                    }
                }
            } else {
                try {
                    FileUtils.deleteDirectory(file);
                } catch (Exception ignored) {
                }
            }
            System.out.println("解析耗费时间：" + (System.currentTimeMillis() - start));
        }

    }


    @Override
    public void parse(Long folderId) {
        String openParse = redisService.get("openParse");
        OpenAiConfig openAiConfig = openAiConfigService.find(1L);
        if (openAiConfig == null) {
            System.out.println("apiKey没有配置");
            return;
        }
        if (openAiConfigService.getCount() <= 0) {
            System.out.println("剩余次数没有了，请充值");
            return;
        }
        if(!StringUtils.equalsIgnoreCase(openParse,"1")){
            System.out.println("未开启解析");
            return;
        }
        File root = new File("D:\\red\\redpackage");
        File[] files = root.listFiles();
        if(files == null || files.length == 0 || files.length==1){
            System.out.println("目录下文件数少于2，不处理");
            return;
        }
        if(folderId != null) {
            root = new File("D:\\red\\redpackage\\" + folderId);
        }
        files = root.listFiles();
        if(files == null || files.length == 0) {
            return;
        }
        File[] newFiles = new File[1];
        newFiles[0] = files[0];
        for (File file : newFiles) {
            File[] children = file.listFiles();
            if (children == null || children.length == 0) {
                try {
                    FileUtils.deleteDirectory(file);
                } catch (Exception ignored) {
                }
                continue;
            }
            // 直接删除，不解析了
            if (children.length <3) {
                try {
                    FileUtils.deleteDirectory(file);
                } catch (Exception ignored) {
                }
                continue;
            }

            int totalTasks = children.length;
            int maxConcurrency = totalTasks;
            ExecutorService executor = Executors.newFixedThreadPool(maxConcurrency);
            List<Callable<List<RedPackageInfo.RedPackageItem>>> taskList = new ArrayList<>();
            // 红包个数
            AtomicReference<Integer> count = new AtomicReference<>(0);
            // 构造任务，确保顺序
            for (int i = 0; i < totalTasks; i++) {
                final int taskId = i;
                taskList.add(() -> {
                    FileSystemResource resource = new FileSystemResource(children[taskId]);
                    UserMessage userMessage = UserMessage.builder()
                            .text(CommonAttributes.PROMPT)
                            .media(new Media(MimeTypeUtils.IMAGE_PNG, resource)).build();
                    try {
                        String s = DateUtils.formatDateToString(new Date(), "yyyy-MM-dd HH:mm:ss");
                        System.out.println(taskId+"：start:" + s);
                        RedPackageInfo entity = chatClient.prompt().messages(userMessage).call().entity(new ParameterizedTypeReference<RedPackageInfo>() {
                        });
                        if(entity!=null){
                            if(entity.getCount()!=null && entity.getCount()>0){
                                count.set(entity.getCount());
                            }
                            return entity.getRedPackageItemList();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                });
            }

            List<Future<List<RedPackageInfo.RedPackageItem>>> futures = null;
            try {
                futures = executor.invokeAll(taskList);
            } catch (InterruptedException ignored) {
            }finally {
                for (File child : children) {
                    try {
                        FileUtils.delete(child);
                    }catch (Exception ignored){
                    }
                }
            }
            List<RedPackageInfo.RedPackageItem> list = new ArrayList<>();
            // 获取并输出结果（保持顺序）
            for (int i = 0; i < totalTasks; i++) {
                try {
                    list.addAll(futures.get(i).get());
                } catch (ExecutionException | InterruptedException e) {
                    System.out.println("任务失败: " + e.getMessage());
                }
                String s = DateUtils.formatDateToString(new Date(), "yyyy-MM-dd HH:mm:ss");
                System.out.println(i+"：end:" + s);
            }
            executor.shutdown();

            List<RedPackage> items = new ArrayList<>();
            // 剔除重复的
            Map<String, RedPackageInfo.RedPackageItem> redPackageItemHashMap = new HashMap<>();
            list.forEach(item -> {
                RedPackage redPackage = new RedPackage();
                redPackage.setBatchId(Long.valueOf(file.getName()));
                redPackage.setName(item.getName());
                try {
                    redPackage.setMoney(item.getAmount());
                } catch (Exception e) {
                    redPackage.setMoney(item.getAmount());
                }
                redPackage.setTime(item.getTime());
                if(StringUtils.startsWith(redPackage.getTime(),"昨日")){
                    redPackage.setFullTime(DateUtils.formatDateToString(DateUtils.getNextDay(-1),"yyyy-MM-dd")+" "+redPackage.getTime());
                }else{
                    redPackage.setFullTime(DateUtils.formatDateToString(new Date(),"yyyy-MM-dd")+" "+redPackage.getTime());
                }
                try {
                    Pattern pattern = Pattern.compile("\\d+\\.\\d+");
                    Matcher matcher = pattern.matcher(redPackage.getMoney()+"");
                    if (matcher.find()) {
                        double moneyDouble = Double.parseDouble(matcher.group());
                        int v = Double.valueOf((moneyDouble * 100)).intValue();
                        int i = v % 10;
                        int j = v / 10;
                        redPackage.setSum(i+j);
                        redPackage.setIsOdd(redPackage.getSum()%2==0?0:1);
                    }
                }catch (Exception ignored){}
                if(redPackage.getMoney()>0 && !redPackageItemHashMap.containsKey(item.getKey())){
                    items.add(redPackage);
                    redPackageItemHashMap.put(item.getKey(), item);
                }
            });
            /**
             * 最终结果 肯定是count<= items 的长度
             */
            System.out.println(count+":"+items.size());
            if(!items.isEmpty()){
                new Thread(()->{
                    batchSave(items);
                }).start();
            }
            openAiConfigService.updateCount(-1*children.length);
            try {
                FileUtils.deleteDirectory(file);
            } catch (Exception ignored) {
            }
        }
    }


    private void save(RedPackageInfo entity) {
        List<RedPackage> redPackages = new ArrayList<>();
        entity.getRedPackageItemList().forEach(item -> {
            RedPackage redPackage = new RedPackage();
            redPackage.setBatchId(entity.getBatchId());
            redPackage.setMoney(item.getAmount());
            redPackage.setName(item.getName());
            redPackage.setTime(item.getTime());
            if(StringUtils.startsWith(redPackage.getTime(),"昨日")){
                Date fullTime = DateUtils.formatStringToDate(DateUtils.formatDateToString(DateUtils.getNextDay(-1),"yyyy-MM-dd")+" "+redPackage.getTime(),"yyyy-MM-dd HH:mm:ss");
                redPackage.setFullTime(DateUtils.formatDateToString(fullTime,"yyyy-MM-dd HH:mm:ss"));
            }else{
                Date fullTime = DateUtils.formatStringToDate(DateUtils.formatDateToString(new Date(),"yyyy-MM-dd")+" "+redPackage.getTime(),"yyyy-MM-dd HH:mm:ss");
                redPackage.setFullTime(DateUtils.formatDateToString(fullTime,"yyyy-MM-dd HH:mm:ss"));
            }
            try {
                Pattern pattern = Pattern.compile("\\d+\\.\\d+");
                Matcher matcher = pattern.matcher(redPackage.getMoney()+"");
                if (matcher.find()) {
                    double moneyDouble = Double.parseDouble(matcher.group());
                    int v = Double.valueOf((moneyDouble * 100)).intValue();
                    int i = v % 10;
                    int j = v / 10;
                    redPackage.setSum(i+j);
                    redPackage.setIsOdd(redPackage.getSum()%2==0?0:1);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            redPackages.add(redPackage);
        });
        batchSave(redPackages);
    }

    private void batchSave(List<RedPackage> results) {
        Date begin = null;
        if (results==null || results.isEmpty()) {
            return;
        }
        Long batchId = results.getFirst().getBatchId();
        for (int i = 0; i < results.size(); i++) {
            RedPackage logNewsReadEntity = results.get(i);
            if(begin == null){
                begin = DateUtils.formatStringToDate(results.getLast().getFullTime(),"yyyy-MM-dd HH:mm:ss");
            }
            Object[] obj = new Object[8];
            // orders
            obj[0] = results.size()-i;
            // batchId
            obj[1] = logNewsReadEntity.getBatchId();
            // money
            obj[2] = logNewsReadEntity.getMoney();
            // name
            obj[3] = logNewsReadEntity.getName();
            // sum
            obj[4] = logNewsReadEntity.getSum();
            // time
            obj[5] = logNewsReadEntity.getTime();
            // fullTime
            obj[6] = logNewsReadEntity.getFullTime();
            // sum
            obj[7] = logNewsReadEntity.getSum()%2;
            int update = jdbcTemplate.update("insert into redpackage(createdDate, lastModifiedDate, version, orders, batchId, money, name, sum, time,fullTime,isOdd) value (NOW(),NOW(),0," + obj[0] + "," + obj[1] + "," + obj[2] + ",'" + obj[3] + "'," + obj[4] + ",'" + obj[5] + "','" + obj[6] + "'," + obj[7] + ") on duplicate key update version=version+1,lastModifiedDate=NOW()");
            System.out.println(update);
        }

        adjust(batchId);
        redPackageStatisticsService.create(results.size(),batchId);
    }

    private void adjust(Long batchId) {
        List<RedPackage> redPackages = getRedPackageByFolderId(batchId);
        for(int i = 0 ; i < redPackages.size() ; i++){
            RedPackage redPackage = redPackages.get(i);
            redPackage.setOrder(i+1);
            super.update(redPackage);
        }
        Date start = DateUtils.formatStringToDate(redPackages.getFirst().getFullTime(),"yyyy-MM-dd HH:mm:ss");
        Date end = DateUtils.formatStringToDate(redPackages.getLast().getFullTime(),"yyyy-MM-dd HH:mm:ss");
        Long interval= DateUtils.getIntervalSecond(start,end);
        if(interval<15){
            interval = 15-interval;
        }
        System.out.println(batchId);
        System.out.println(start);
        System.out.println(end);
        System.out.println(interval);
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select time from redpackage where batchId=? group by time", batchId);
        maps.forEach(item->{
            String time = (String)item.get("time");
            List<RedPackage> redPackages1 = getRedPackageByFolderIdAndTime(batchId,time);
            int avgDuration = 1000/(redPackages1.size()+1);
            for (int i = 0; i < redPackages1.size(); i++) {
                RedPackage redPackage = redPackages1.get(i);
                redPackage.setOpenTime(DateUtils.getIntervalSecond(start,DateUtils.formatStringToDate(redPackage.getFullTime(),"yyyy-MM-dd HH:mm:ss"))*1000+((long) avgDuration *(i+1)));
                jdbcTemplate.update("update redpackage set openTime=? where id=?",redPackage.getOpenTime(),redPackage.getId());
            }
        });
    }

    @Override
    public List<RedPackage> getRedPackageByFolderId(Long batchId) {
        return redPackageDao.getRedPackageByFolderId(batchId);
    }

    @Override
    public List<RedPackage> getRedPackageByFolderIdAndTime(Long batchId, String time) {
        return redPackageDao.getRedPackageByFolderIdAndTime(batchId,time);
    }


    @Override
    public Page<RedPackage> findPage(Pageable pageable,Long sn) {
        org.springframework.data.domain.Page<RedPackage> result = redPackageRepository.findAll(new Specification<RedPackage>() {
            @Override
            public Predicate toPredicate(Root<RedPackage> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();
                return predicate;
            }
        }, org.springframework.data.domain.Pageable.ofSize(pageable.getPageSize()).withPage(pageable.getPageNumber() - 1));
        return new Page<>(result.getContent(), result.getTotalElements(), pageable) ;
    }
}
